#include <vector>
#include <boost/foreach.hpp>
#include "Game.h"
#include "ResourceManager.h"

#define foreach BOOST_FOREACH

using namespace sf;
using namespace std;

Game::Game():
window(VideoMode(1024, 640), "Hoho Mario"),
render(&window),
collisionManager(CollisionManager::getInstance())
{
	window.UseVerticalSync(true);
	initPhysics();

	ResourceManager* resManager = ResourceManager::getInstance();
	vector<AnimationDefinition> animDefs = resManager->loadAnimationFromXML("../media/player.xml");
	Image* img = resManager->loadImage("../media/player.png");
	img->CreateMaskFromColor(img->GetPixel(0,0));
	AnimatedSprite* sprite = new AnimatedSprite(*img, animDefs);
	sprite->setAnimation("idle");
	sprite->SetCenter(15.5f, 15.5f);
	//sprite->Scale(1.0f, 1.0f);
	

	b2BodyDef bodyDef;
	bodyDef.fixedRotation = true;
	bodyDef.position.Set(0.0f, 0.0f);
	b2Body* body = world->CreateBody(&bodyDef);

	b2PolygonDef shapeDef;
	shapeDef.SetAsBox(0.7f, 1.4f, b2Vec2(-0.1f, -0.1f), 0);
	shapeDef.density = 0.5f;
	shapeDef.friction = 0.5f;
	b2Shape* playerBody = body->CreateShape(&shapeDef);

	body->SetMassFromShapes();
	body->AllowSleeping(false);

	
	player = new Player(sprite, body);

	render.setPlayer(player);

	MapInfo info = resManager->loadMapInfo("ground");
	foreach(const Sprite& s, info.sprites) {
		render.addSprite(s);
	}

	// Define the ground body.
	b2BodyDef groundBodyDef;
	groundBodyDef.position.Set(0.0f, 0.0f);
	// Call the body factory which allocates memory for the ground body
	// from a pool and creates the ground box shape (also from a pool).
	// The body is also added to the world.
	b2Body* groundBody = world->CreateBody(&groundBodyDef);
	groundBody->SetUserData("ground");
	// Define the ground box shape.
	foreach (b2EdgeChainDef shape, info.bounds) {
		groundBody->CreateShape(&shape);
		delete [] shape.vertices;
	}

	inputManager = new InputManager(&window, player);
}

Game::~Game()
{
	delete inputManager;
	delete player;
	delete world;
}

void Game::initPhysics()
{
	b2AABB worldAABB;
	worldAABB.upperBound.Set(250.0f, 1000.0f);
	worldAABB.lowerBound.Set(-250.0f, -250.0f);
	
	// Define the gravity vector.
	b2Vec2 gravity(0.0f, -9.81f);
	// Construct a world object, which will hold and simulate the rigid bodies.
	world = new b2World(worldAABB, gravity, true);
	//world->SetDebugDraw(render.getDebugView());
	world->SetContactListener(collisionManager);
}

bool Game::isRunning()
{
	return window.IsOpened();
}

void Game::update()
{
	float timeStep = window.GetFrameTime();
	// Process events
    Event evt;
    while (window.GetEvent(evt))
    {
		// Close window : exit
        if (evt.Type == Event::Closed)
            window.Close();
		// Escape key : exit
        if ((evt.Type == Event::KeyPressed) && (evt.Key.Code == Key::Escape))
            window.Close();
    }
	inputManager->processInput(timeStep);
	render.clear();
	world->Step(1.0f/60.0f, 8, 3);
	render.update(timeStep);
}
